﻿#pragma once

#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>

#include "../NavData.h"

namespace ns_GNSSMesData
{
	using namespace ns_Data;

	struct GNSSMesHeader : public NavData
	{
	public:
		using Ptr = std::shared_ptr<GNSSMesHeader>;
		using VersonType = std::string;

		struct TimeSysCorr
		{
			double A0;
			double A1;
			double T;
			double W;
		};

	public:
		VersonType version;		 // 版本号
		GNSSType gnssType;		 // 属于哪个卫星系统的数据
		double ionAlpha[4];		 // 电离层改正参数α
		double ionBeta[4];		 // 电离层改正参数β
		TimeSysCorr timeSysCorr; // 时间改正参数
		long leapSecond;		 // 跳秒
		long size;
		long recNum;

	public:
		virtual bool Encode(std::string *outJson) const override
		{
			if (outJson == nullptr)
				return false;

			Json::Value outValue;
			outValue["Type"] = "GNSSMesHeader";
			outValue["Version"] = version;
			outValue["GNSSType"] = static_cast<int>(gnssType);
			for (int i = 0; i < 4; ++i)
			{
				outValue["IonAlpha"][i] = ionAlpha[i];
				outValue["IonBeta"][i] = ionBeta[i];
			}

			Json::Value timeSysCorrValue;
			timeSysCorrValue["A0"] = timeSysCorr.A0;
			timeSysCorrValue["A1"] = timeSysCorr.A1;
			timeSysCorrValue["T"] = timeSysCorr.T;
			timeSysCorrValue["W"] = timeSysCorr.W;

			outValue["TimeSysCorr"] = timeSysCorrValue;
			outValue["LeapSecond"] = leapSecond;
			outValue["Size"] = size;
			outValue["RecNum"] = recNum;

			Json::FastWriter writer;
			*outJson = writer.write(outValue);

			return true;
		}

		virtual bool Decode(const std::string &inJson) override
		{
			Json::Value inValue;
			Json::Reader reader;
			bool parsingSuccessful = reader.parse(inJson, inValue);
			if (!(parsingSuccessful && inValue["Type"] == "GNSSMesHeader"))
			{
				return false;
			}

			version = inValue["Version"].asString();
			gnssType = static_cast<GNSSType>(inValue["GNSSType"].asInt());

			for (int i = 0; i < 4; ++i)
			{
				ionAlpha[i] = inValue["IonAlpha"][i].asDouble();
				ionBeta[i] = inValue["IonBeta"][i].asDouble();
			}

			timeSysCorr.A0 = inValue["TimeSysCorr"]["A0"].asDouble();
			timeSysCorr.A1 = inValue["TimeSysCorr"]["A1"].asDouble();
			timeSysCorr.T = inValue["TimeSysCorr"]["T"].asDouble();
			timeSysCorr.W = inValue["TimeSysCorr"]["W"].asDouble();

			leapSecond = inValue["LeapSecond"].asInt();
			size = inValue["Size"].asInt();
			recNum = inValue["RecNum"].asInt();

			return true;
		}
	};

	struct GNSSMesRecord : public NavData
	{
	public:
		using Ptr = std::shared_ptr<GNSSMesRecord>;

	public:
		GNSSType gnssType;
		int serial; // 序列号

		double year;
		double month;
		double day;
		double hour;
		double minute;
		double second; // 年月日时分秒

		double a0;	 // 卫星钟差
		double a1;	 // 卫星钟偏
		double a2;	 // 卫星钟偏移
		double AODE; // 数据龄期

		double crs;		   // 轨道半径改正项
		double deltan;	   // 平均角速度改正项
		double M0;		   // 平近点角
		double cuc;		   // 升交点角距改正项
		double e;		   // 轨道偏心率
		double cus;		   // 升交点角距改正项
		double sqrtA;	   // 轨道长半轴平方根
		double TOE;		   // 星历的参考时刻  周内秒
		double cic;		   // 轨道倾角的改正项
		double OMEGA;	   // 升交点经度
		double cis;		   // 轨道倾角改正项
		double i0;		   // 轨道倾角
		double crc;		   // 轨道半径的改正项
		double omega;	   // 近地点角距
		double deltaOmega; // 升交点赤经变化
		double IDOT;	   // 轨道倾角的变率
		// 对于单点定位，以上数据足以，但是为了保持卫星数据完整，以下保持了所有的数据

		double CA;		  // CA码
		double GPSWeek;	  // gps周数
		double L2P;		  // L2P码
		double SVA;		  // 卫星精度
		double SVH;		  // 卫星健康
		double TGD;		  // 电离层延迟
		double IODC;	  // 数据质量
		double shootTime; // 发射时间
		double h;		  // 拟合区间

		virtual bool Encode(std::string *outJson) const override
		{
			if (outJson == nullptr)
				return false;

			Json::Value outValue;
			outValue["Type"] = "GNSSMesRecord";

			outValue["GNSSType"] = gnssType;
			outValue["Serial"] = serial;
			outValue["Year"] = year;
			outValue["Month"] = month;
			outValue["Day"] = day;
			outValue["Hour"] = hour;
			outValue["Minute"] = minute;
			outValue["Second"] = second;

			outValue["A0"] = a0;
			outValue["A1"] = a1;
			outValue["A2"] = a2;
			outValue["AODE"] = AODE;

			outValue["Crs"] = crs;
			outValue["DeltaN"] = deltan;
			outValue["M0"] = M0;
			outValue["Cuc"] = cuc;
			outValue["E"] = e;
			outValue["Cus"] = cus;
			outValue["SqrtA"] = sqrtA;
			outValue["TOE"] = TOE;
			outValue["Cic"] = cic;
			outValue["I0"] = i0;
			outValue["Crc"] = crc;
			outValue["Omega"] = omega;
			outValue["DeltaOmega"] = deltaOmega;
			outValue["IDOT"] = IDOT;

			outValue["CA"] = CA;
			outValue["GPSWeek"] = GPSWeek;
			outValue["L2P"] = L2P;
			outValue["SVA"] = SVA;
			outValue["SVH"] = SVH;
			outValue["TGD"] = TGD;
			outValue["IODC"] = IODC;
			outValue["ShootTime"] = shootTime;
			outValue["H"] = h;

			Json::FastWriter writer;
			std::string outString = writer.write(outValue);

			*outJson = outString;

			return true;
		}

		virtual bool Decode(const std::string &inJson) override
		{
			Json::Value inValue;
			Json::Reader reader;
			bool parsingSuccessful = reader.parse(inJson, inValue);
			if (!(parsingSuccessful && inValue["Type"].asString() == "GNSSMesRecord"))
				return false;

			// 解析 JSON 并赋值给成员变量
			gnssType = static_cast<GNSSType>(inValue["GNSSType"].asInt());
			serial = inValue["Serial"].asInt();
			year = inValue["Year"].asDouble();
			month = inValue["Month"].asDouble();
			day = inValue["Day"].asDouble();
			hour = inValue["Hour"].asDouble();
			minute = inValue["Minute"].asDouble();
			second = inValue["Second"].asDouble();

			a0 = inValue["A0"].asDouble();
			a1 = inValue["A1"].asDouble();
			a2 = inValue["A2"].asDouble();
			AODE = inValue["AODE"].asDouble();

			crs = inValue["Crs"].asDouble();
			deltan = inValue["DeltaN"].asDouble();
			M0 = inValue["M0"].asDouble();
			cuc = inValue["Cuc"].asDouble();
			e = inValue["E"].asDouble();
			cus = inValue["Cus"].asDouble();
			sqrtA = inValue["SqrtA"].asDouble();
			TOE = inValue["TOE"].asDouble();
			cic = inValue["Cic"].asDouble();
			i0 = inValue["I0"].asDouble();
			crc = inValue["Crc"].asDouble();
			omega = inValue["Omega"].asDouble();
			deltaOmega = inValue["DeltaOmega"].asDouble();
			IDOT = inValue["IDOT"].asDouble();

			CA = inValue["CA"].asDouble();
			GPSWeek = inValue["GPSWeek"].asDouble();
			L2P = inValue["L2P"].asDouble();
			SVA = inValue["SVA"].asDouble();
			SVH = inValue["SVH"].asDouble();
			TGD = inValue["TGD"].asDouble();
			IODC = inValue["IODC"].asDouble();
			shootTime = inValue["ShootTime"].asDouble();
			h = inValue["H"].asDouble();

			return true;
		}
	};

	// 单个数据
	class GNSSMesData : public NavData
	{
	public:
		using Ptr = std::shared_ptr<GNSSMesData>;

	public:
		GNSSMesData()
		{
		}

		GNSSMesData(const GNSSMesHeader::Ptr& header,const GNSSMesRecord::Ptr& record, GNSSType type)
			: _header(header),
			  _record(record),
			  _GNSSName(type)
		{
		}

		GNSSMesHeader::Ptr GetHeader()
		{
			return _header;
		}

		GNSSMesRecord::Ptr GetRecord()
		{
			return _record;
		}

		GNSSType GetGNSSType()
		{
			return _GNSSName;
		}

	private:
		GNSSMesHeader::Ptr _header;
		GNSSMesRecord::Ptr _record;

		GNSSType _GNSSName;

	public:
		virtual bool Encode(std::string *outJson) const override
		{
			if (outJson == nullptr)
				return false;

			if (_header == nullptr || _record == nullptr)
				return false;

			std::string headerJson, recordJson;
			_header->Encode(&headerJson);
			_record->Encode(&recordJson);

			Json::Reader reader;

			Json::Value headerValue, recordValue;
			reader.parse(headerJson, headerValue);
			reader.parse(recordJson, recordValue);

			Json::Value outValue;
			outValue["Type"] = "GNSSMesData";
			outValue["GNSSType"] = static_cast<int>(_GNSSName);
			outValue["Header"] = headerValue;
			outValue["Record"] = recordValue;

			Json::FastWriter writer;
			*outJson = writer.write(outValue);

			return true;
		}

		virtual bool Decode(const std::string &inJson) override
		{
			Json::Reader reader;
			Json::Value inValue;

			bool parsingSuccessful = reader.parse(inJson, inValue);
			if (!(parsingSuccessful && inValue["Type"] == "GNSSMesData"))
			{
				return false;
			}

			_GNSSName = static_cast<GNSSType>(inValue["GNSSType"].asInt());

			_header = std::make_shared<GNSSMesHeader>();
			_record = std::make_shared<GNSSMesRecord>();

			std::string headerJson, recordJson;
			headerJson = JsonUtil::ValueToString(inValue["Header"]);
			recordJson = JsonUtil::ValueToString(inValue["Record"]);

			if (_header->Decode(headerJson) &&
				_record->Decode(recordJson))
				return true;

			return false;
		}
	};
}